home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue30 / bdeorx / BDEDORX.ZIP / Px7Tbl / PX7TABLE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-12-22  |  9.9 KB  |  340 lines

  1. unit Px7Table;
  2.  
  3. (*
  4.  
  5. ***************************************************************
  6. *                                                             *
  7. *  Px7Table compoment                                         *
  8. *                                                             *
  9. *  (c) 1996-97 Reinhard Kalinke                               *
  10. *                                                             *
  11. *  R_Kalinke@compuserve.com                                   *
  12. *                                                             *
  13. ***************************************************************
  14.  
  15. This is a TTable descendant with an added method to make use of
  16. the new Pdox7 descending indices. With this type of index, you
  17. can determine the sortorder for every single field in the index.
  18. It also adds an event that will be trigerred on certain open errors
  19. like 'index out of date' or files/tables related with the table are
  20. missing. Finally it implements autosaving changes to disk.
  21.  
  22. *)
  23.  
  24. interface
  25.  
  26. uses
  27.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  28.   Forms, Dialogs, DB, DBTables, DBConsts, DBITypes;
  29.  
  30. type
  31.   TPDXOpenFailType = (ofNone,ofIndexOutOfDate,ofMBMissing,ofLookUpMissing,
  32.                       ofDetailMissing,ofMasterMissing,ofValFileCorrupt);
  33.   TPDXOpenFailure = procedure(Sender: TObject; FailType: TPDXOpenFailType) of object;
  34.   TPx7Table = class(TTable)
  35.   private
  36.     FFailType: TPDXOpenFailType;
  37.     FOnOpenFailure: TPDXOpenFailure;
  38.     FAutoSaveChanges: boolean;
  39.     FAutoChangeLevel: boolean;
  40.     procedure EncodePx7IndexDesc(var IndexDesc: IDXDesc;
  41.       const Name, Fields, DescFields: string;
  42.       Options: TIndexOptions);
  43.     function IsPxTable: Boolean;
  44.     procedure SetAutoSaveChanges(Value: boolean);
  45.     procedure SetAutoChangeLevel(Value: boolean);
  46.   protected
  47.     function CreateHandle: hDBICur; override;
  48.     procedure DoAfterPost; override;
  49.     procedure DoAfterDelete; override;
  50.   public
  51.     constructor Create(AOwner: TComponent); override;
  52.     procedure AddPx7Index(const Name, Fields, DescFields: string;
  53.       Options: TIndexOptions);
  54.     function GetDescFields(const IxName: string): string;
  55.     function GetLevel: string;
  56.     procedure SetLevel(ALevel: string);
  57.   published
  58.     property AutoSaveChanges: boolean
  59.       read FAutoSaveChanges write SetAutoSaveChanges default True;
  60.     property AutoChangeLevel: boolean
  61.       read FAutoChangeLevel write SetAutoChangeLevel default True;
  62.     property OnOpenFailure: TPDXOpenFailure
  63.       read FOnOpenFailure write FOnOpenFailure;
  64.   end;
  65.  
  66. procedure Register;
  67.  
  68. implementation
  69.  
  70. uses DBIProcs, DBIErrs;
  71.  
  72. constructor TPx7Table.Create(AOwner: TComponent);
  73. begin
  74.   inherited Create(AOwner);
  75.   FAutoSaveChanges := True;
  76.   FAutoChangeLevel := True;
  77. end;
  78.  
  79. function TPx7Table.CreateHandle: hDBICur;
  80. var BDEError: DBIResult;
  81.     i: integer;
  82. begin
  83.   try try
  84.     Result := inherited CreateHandle;
  85.   except
  86.     on E:EDBEngineError do
  87.     begin
  88.       for i:=0 to pred(E.ErrorCount) do
  89.       begin
  90.         BDEError := E.Errors[i].ErrorCode;
  91.         if (BDEError = DBIERR_INDEXOUTOFDATE) then
  92.           FFailType := ofIndexOutOfDate
  93.         else
  94.         if (BDEError = DBIERR_LOOKUPTBLOPENERR) then
  95.           FFailType := ofLookupMissing
  96.         else
  97.         if (BDEError = DBIERR_DETAILTBLOPENERR) then
  98.           FFailType := ofDetailMissing
  99.         else
  100.         if (BDEError = DBIERR_MASTERTBLOPENERR) then
  101.           FFailType := ofMasterMissing
  102.         else
  103.         if (BDEError = DBIERR_VALFILECORRUPT) then
  104.           FFailType := ofValFileCorrupt
  105.         else
  106.         if (BDEError = DBIERR_BLOBFILEMISSING) then
  107.           FFailType := ofMBMissing;
  108.       end;
  109.       if (FFailType <> ofNone) then
  110.         Sysutils.Abort
  111.       else raise;
  112.     end;{}
  113.   end;
  114.   finally
  115.     if (FFailType <> ofNone)
  116.     and Assigned(FOnOpenFailure) then
  117.       FOnOpenFailure(Self, FFailType);
  118.     FFailType := ofNone;
  119.   end;
  120. end;
  121.  
  122. procedure TPx7Table.DoAfterPost;
  123. begin
  124.   if FAutoSaveChanges then
  125.     DBISaveChanges(Handle);
  126.   inherited DoAfterPost;
  127. end;
  128.  
  129. procedure TPx7Table.DoAfterDelete;
  130. begin
  131.   if FAutoSaveChanges then
  132.     DBISaveChanges(Handle);
  133.   inherited DoAfterDelete;
  134. end;
  135.  
  136. function TPx7Table.GetDescFields(const IxName: string): string;
  137. var IxDesc: IDXDesc;
  138.     IxNo: word;
  139.     szIxStr: DBIName;
  140.     i,j: integer;
  141. begin
  142.   Result := '';
  143.   {$IFNDEF VER100}
  144.   if not Active then DBError(SDataSetClosed);
  145.   {$ELSE}
  146.   if not Active then DataBaseError(SDataSetClosed);
  147.   {$ENDIF}
  148.   StrPCopy(szIxStr, IxName);
  149.   Check( DBIGetIndexSeqNo(Handle, szIxStr, nil, 0, IxNo) );
  150.   Check( DBIGetIndexDesc(Handle, IxNo, IxDesc) );
  151.   with FieldDefs, IxDesc do
  152.   begin
  153.     Update;
  154.     {$IFDEF WIN32}
  155.     for i := 0 to high(abDescending) do
  156.       if abDescending[i] then
  157.     {$ELSE}
  158.     for i := 0 to high(iUnUsed) do
  159.       if (iUnUsed[i] = 1) then
  160.     {$ENDIF}
  161.         for j := 0 to pred(Count) do
  162.           if FieldDefs[j].FieldNo = aiKeyFld[i] then
  163.           begin
  164.             Result := Result + FieldDefs[j].Name + ';';
  165.             Break;
  166.           end;
  167.     if Result > '' then
  168.       {$IFDEF WIN32}
  169.       SetLength(Result,pred(Length(Result)));
  170.       {$ELSE}
  171.       Result[0] := char(pred(Length(Result)));
  172.       {$ENDIF}
  173.   end;
  174. end;
  175.  
  176. procedure TPx7Table.AddPx7Index(const Name, Fields,
  177.                                 DescFields: string;
  178.                                 Options: TIndexOptions);
  179. var
  180.   STableName: DBITBLNAME;
  181.   IndexDesc: IDXDesc;
  182. begin
  183.   if (DescFields > '') and (GetLevel < '7') then
  184.   begin
  185.     if FAutoChangeLevel then
  186.       SetLevel('7')
  187.     else
  188.       raise Exception.Create('Table level 7 required');
  189.   end;
  190.   if not IsPxTable then
  191.     AddIndex(Name, Fields, Options) {or raise an exception}
  192.   else
  193.   begin
  194.     FieldDefs.Update;
  195.     EncodePx7IndexDesc(IndexDesc, Name, Fields, DescFields, Options);
  196.     if Active then
  197.     begin
  198.       CheckBrowseMode;
  199.       CursorPosChanged;
  200.       Check(DbiAddIndex(DBHandle, Handle, nil, nil, IndexDesc, nil));
  201.     end else
  202.     begin
  203.       SetDBFlag(dbfTable, True);
  204.       try
  205.         Check(DbiAddIndex(DBHandle, nil, AnsiToNative(DBLocale, TableName,
  206.           STableName, SizeOf(STableName) - 1), szParadox,
  207.           IndexDesc, nil));
  208.       finally
  209.         SetDBFlag(dbfTable, False);
  210.       end;
  211.     end;
  212.     DataEvent(dePropertyChange, 0);
  213.   end;
  214. end;
  215.  
  216. procedure TPx7Table.EncodePx7IndexDesc(var IndexDesc: IDXDesc;
  217.   const Name, Fields, DescFields: string; Options: TIndexOptions);
  218. var
  219.   iPos, jPos: Integer;
  220. begin
  221.   FillChar(IndexDesc, SizeOf(IndexDesc), 0);
  222.   with IndexDesc do
  223.   begin
  224.     AnsiToNative(DBLocale, Name, szName, SizeOf(szName) - 1);
  225.     bPrimary := ixPrimary in Options;
  226.     bUnique := ixUnique in Options;
  227.     bDescending := ixDescending in Options;
  228.     bCaseInsensitive := ixCaseInsensitive in Options;
  229.     bMaintained := True;
  230.     iPos := 1;
  231.     while (iPos <= Length(Fields)) and (iFldsInKey < 16) do
  232.     begin
  233.       jPos := iPos;
  234.       aiKeyFld[iFldsInKey] :=
  235.         FieldDefs.Find(ExtractFieldName(Fields,iPos)).FieldNo;
  236.       {this is the one that makes a field descending:}
  237.       if bDescending
  238.       and (pos(ExtractFieldName(Fields,jPos),DescFields)<>0) then
  239.         {$IFDEF WIN32}
  240.         abDescending[iFldsInKey] := True;
  241.         {$ELSE}
  242.         iUnUsed[iFldsInKey] := 1;
  243.         {$ENDIF}
  244.       Inc(iFldsInKey);
  245.     end;
  246.   end;
  247. end;
  248.  
  249. function TPx7Table.IsPxTable: Boolean;
  250. begin
  251.   Result := (TableType = ttParadox) or
  252.     (CompareText(ExtractFileExt(TableName), '.DB') = 0);
  253. end;
  254.  
  255. function TPx7Table.GetLevel: string;
  256. var TblProps: CURProps;
  257. begin
  258.   {$IFNDEF VER100}
  259.   if not Active then DBError(SDataSetClosed);
  260.   {$ELSE}
  261.   if not Active then DataBaseError(SDataSetClosed);
  262.   {$ENDIF}
  263.   Check(DBIGetCursorProps(Handle,TblProps));
  264.   Result := IntToStr(TblProps.iTblLevel);
  265. end;
  266.  
  267. procedure TPx7Table.SetLevel(ALevel: string);
  268. var hDB: hDBIdb;
  269.     TblProps: CURProps;
  270.     pTableDesc: pCRTblDesc;
  271.     pOptFldDesc: pFLDDesc;
  272.     szLevel: DBIName;
  273. begin
  274.   {$IFNDEF VER100}
  275.   if not Active then DBError(SDataSetClosed);
  276.   {$ELSE}
  277.   if not Active then DataBaseError(SDataSetClosed);
  278.   {$ENDIF}
  279.   pTableDesc := nil;
  280.   pOptFldDesc := nil;
  281.   Check(DBIGetCursorProps(Handle,TblProps));
  282.   if (TblProps.iTblLevel <> StrToInt(ALevel)) then
  283.   try
  284.     DisableControls;
  285.     GetMem(pTableDesc,sizeOf(CRTblDesc));
  286.     FillChar(pTableDesc^,sizeOf(CRTblDesc),0);
  287.     GetMem(pOptFldDesc,sizeOf(FLDDesc));
  288.     FillChar(pOptFldDesc^,sizeOf(FLDDesc),0);
  289.     with pTableDesc^ do
  290.     begin
  291.       AnsiToNative(DBLocale,TableName,szTblName,255);
  292.       StrPCopy(szTblType,TblProps.szTableType);
  293.       bProtected := TblProps.bProtected;
  294.       StrPCopy(pOptFldDesc^.szName,'LEVEL');
  295.       pOptFldDesc^.iLen := length(ALevel)+1;
  296.       pFldOptParams := pOptFldDesc;
  297.       StrPCopy(szLevel,ALevel);
  298.       pOptData := @szLevel;
  299.       iOptParams := 1;
  300.       hDB := DBHandle;
  301.       Close;
  302.       Check( DBIDoRestructure(hDB,        {DB handle}
  303.                               1,          {no of tbls (has to be 1)}
  304.                               pTableDesc, {table data desc.}
  305.                               nil,        {pSaveAs}
  306.                               nil,        {pKeyViol}
  307.                               nil,        {pProblem}
  308.                               False) );   {Analyze only}
  309.     end;
  310.   finally
  311.     if pTableDesc <> nil then
  312.       FreeMem(pTableDesc,sizeOf(CRTblDesc));
  313.     if pOptFldDesc <> nil then
  314.       FreeMem(pOptFldDesc,SizeOf(FLDDesc));
  315.     Open;
  316.     EnableControls;
  317.   end;
  318. end;
  319.  
  320. procedure TPx7Table.SetAutoSaveChanges(Value: boolean);
  321. begin
  322.   if (FAutoSaveChanges <> Value) then
  323.     FAutoSaveChanges := Value;
  324. end;
  325.  
  326. procedure TPx7Table.SetAutoChangeLevel(Value: boolean);
  327. begin
  328.   if (FAutoChangeLevel <> Value) then
  329.     FAutoChangeLevel := Value;
  330. end;
  331.  
  332. {-----------------}
  333.  
  334. procedure Register;
  335. begin
  336.   RegisterComponents('DBAddOns', [TPx7Table]);
  337. end;
  338.  
  339. end.
  340.